package com.hcmed;

import android.Manifest;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.hardware.Sensor;
import android.hardware.SensorEvent;
import android.hardware.SensorEventListener;
import android.hardware.SensorManager;
import android.os.Build;
import android.os.Bundle;
import android.util.Log;
import android.view.*;
import android.widget.*;
import androidx.annotation.RequiresApi;
import androidx.appcompat.app.AppCompatActivity;
import cn.hutool.http.HttpException;
import cn.hutool.http.HttpResponse;
import cn.hutool.http.HttpUtil;
import cn.hutool.json.JSONUtil;
import org.apache.commons.lang3.StringUtils;

import java.time.LocalDateTime;
import java.time.ZoneId;
import java.util.*;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.atomic.AtomicReference;

/**
 * @author 暗影孤星
 * @date 2021/2/2 23:38
 * @description 主界面
 */
public class MainActivity extends AppCompatActivity implements SensorEventListener {

    private int axisX;
    private int axisY;
    private final float[] accValues = new float[3];
    private final float[] magValues = new float[3];

    /**
     * 蓝牙适配器
     */
    private BluetoothAdapter mBluetoothAdapter;

    /**
     * 蓝牙设备
     */
    private BluetoothDevice bluetoothDevice;

    private SensorManager mSensorManager;
    private Sensor mSensorAcc, mSensorMag;

    /**
     * 文本视图：加速度、移动距离、磁力计、方向角、信号距离、信号强度、当前蓝牙
     */
    private TextView accelerationValue, movingDistanceValue, magnetometerValue, angleVale, signalDistanceValue, signalValue, blueName;

    /**
     * 校验加速度
     */
    private Button test;

    /**
     * 蓝牙信号
     */
    private Double rssi;

    /**
     * 下拉框
     */
    Spinner spinner;

    /**
     * 当前蓝牙名称
     */
    private String bluetoothName = "";

    /**
     * 蓝牙名称集合
     */
    private final List<String> bluetoothNameList = new CopyOnWriteArrayList<>();

    /**
     * 数据
     */
    private final List<Double[]> doubleList = new CopyOnWriteArrayList<>();

    /**
     * 定时任务间隔
     */
    private final Long time = 600L;

    /**
     * 加速度集合
     */
    private final List<Double> accelerationList = new CopyOnWriteArrayList<>();

    /**
     * 加速度
     */
    private Double average;
    /**
     * 距离
     */
    private Double distance = 0.0;

    /**
     * 方向角
     */
    private Double angle;

    private final List<Double> accList = new CopyOnWriteArrayList<>();

    /**
     * 距离集合
     */
    private final List<String> distanceList = new CopyOnWriteArrayList<>();

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        // 获取本地蓝牙适配器
        mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
        checkPermission();
        startDiscovery();

        test = findViewById(R.id.test);
        spinner = findViewById(R.id.spinner);
        blueName = findViewById(R.id.blueName);
        angleVale = findViewById(R.id.angleVale);
        signalValue = findViewById(R.id.signalValue);

        accelerationValue = findViewById(R.id.accelerationValue);
        magnetometerValue = findViewById(R.id.magnetometerValue);
        movingDistanceValue = findViewById(R.id.movingDistanceValue);
        signalDistanceValue = findViewById(R.id.signalDistanceValue);

        // 第一步：通过getSystemService获得SensorManager实例对象
        mSensorManager = (SensorManager) getSystemService(Context.SENSOR_SERVICE);
        // 第二步：通过SensorManager实例对象获得想要的传感器对象:参数决定获取哪个传感器
        mSensorAcc = mSensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER);
        mSensorMag = mSensorManager.getDefaultSensor(Sensor.TYPE_MAGNETIC_FIELD);

        // 根据当前上下文的屏幕方向调整与自然方向的相对关系。
        // 当设备的自然方向是竖直方向（比如，理论上说所有手机的自然方向都是都是是竖直方向），
        // 而应用是横屏时，需要将相对设备自然方向的方位角转换为相对水平方向的方位角。
        WindowManager wm = (WindowManager) this.getSystemService(Context.WINDOW_SERVICE);
        Display dis = wm.getDefaultDisplay();
        int rotation = dis.getRotation();
        switch (rotation) {
            case Surface.ROTATION_90:
                axisX = SensorManager.AXIS_Y;
                axisY = SensorManager.AXIS_MINUS_X;
                break;
            case Surface.ROTATION_180:
                axisX = SensorManager.AXIS_X;
                axisY = SensorManager.AXIS_MINUS_Y;
                break;
            case Surface.ROTATION_270:
                axisX = SensorManager.AXIS_MINUS_Y;
                axisY = SensorManager.AXIS_X;
                break;
            default:
                axisX = SensorManager.AXIS_X;
                axisY = SensorManager.AXIS_Y;
                break;
        }
        IntentFilter intentFilter = new IntentFilter();
        intentFilter.addAction(BluetoothDevice.ACTION_FOUND);
//        intentFilter.addAction(BluetoothDevice.ACTION_ACL_CONNECTED);
//        intentFilter.addAction(BluetoothDevice.ACTION_BOND_STATE_CHANGED);
//        intentFilter.addAction(BluetoothAdapter.ACTION_STATE_CHANGED);
//        intentFilter.addAction(BluetoothAdapter.ACTION_DISCOVERY_STARTED);
//        intentFilter.addAction(BluetoothAdapter.ACTION_DISCOVERY_FINISHED);
        getApplicationContext().registerReceiver(mReceiver, intentFilter);

        bluetoothNameList.add("请选择蓝牙");
        setSpinner(bluetoothNameList);

        getAngle();
        getDistance();
        displayDistance();
    }

    /**
     * 设置下拉框
     *
     * @param newBluetoothNameList 蓝牙名称
     */
    private void setSpinner(List<String> newBluetoothNameList) {
        // 设置数据
        ArrayAdapter<String> arrAdapter = new ArrayAdapter<>(this, android.R.layout.simple_spinner_item, newBluetoothNameList);
        // 设置样式
        arrAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
        // 加载适配器
        MainActivity.this.runOnUiThread(() -> spinner.setAdapter(arrAdapter));

        spinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {

            @Override
            public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
                if (position != 0) {
                    Log.e("position", String.valueOf(position));
                    bluetoothName = newBluetoothNameList.get(position);
                    doubleList.clear();
                    MainActivity.this.runOnUiThread(() -> blueName.setText(bluetoothName));
                }
            }

            @Override
            public void onNothingSelected(AdapterView<?> parent) {
            }
        });
    }

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        getMenuInflater().inflate(R.menu.menu_main, menu);
        return true;
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        if (item.getItemId() == R.id.action_settings) {
            return true;
        }

        return super.onOptionsItemSelected(item);
    }

    /**
     * 传感器精度发生改变的回调接口
     */
    @Override
    public final void onAccuracyChanged(Sensor sensor, int accuracy) {
        // TODO 在传感器精度发生改变时做些操作，accuracy为当前传感器精度
    }

    /**
     * 传感器事件值改变时的回调接口：执行此方法的频率与注册传感器时的频率有关
     */
    @Override
    public final void onSensorChanged(SensorEvent event) {
        // 大部分传感器会返回三个轴方向x,y,x的event值，值的意义因传感器而异
        float x = (float) Math.round(event.values[0] * 100) / 100;
        float y = (float) Math.round(event.values[1] * 100) / 100;
        float z = (float) Math.round(event.values[2] * 100) / 100;

        if (event.sensor == mSensorAcc) {
            // 加速度传感器
            accValues[0] = x;
            accValues[1] = y;
            accValues[2] = z;
            accelerationValue.setText("x:" + x + "\ny:" + y + "\nz:" + z);

            // X^2+Y^2+Z^2
            double sqrt = Math.sqrt(Math.pow(x, 2) + Math.pow(y, 2) + Math.pow(z, 2));
            accList.add(sqrt);

            if (average != null && sqrt < average * 1.04 && sqrt > average * 0.96) {
                accelerationList.add(0.0);
            } else {
                accelerationList.add(Math.sqrt(Math.pow(x, 2) + Math.pow(y, 2)));
            }

        } else if (event.sensor == mSensorMag) {
            // 磁力传感器
            magValues[0] = x;
            magValues[1] = y;
            magValues[2] = z;
            magnetometerValue.setText("x:" + x + "\ny:" + y + "\nz:" + z);
        }
    }

    /**
     * 第三步：在获得焦点时注册传感器并让本类实现SensorEventListener接口
     */
    @Override
    protected void onResume() {
        super.onResume();
        /*
         *第一个参数：SensorEventListener接口的实例对象
         *第二个参数：需要注册的传感器实例
         *第三个参数：传感器获取传感器事件event值频率：
         *              SensorManager.SENSOR_DELAY_FASTEST = 0：对应0微秒的更新间隔，最快，1微秒 = 1 % 1000000秒
         *              SensorManager.SENSOR_DELAY_GAME = 1：   对应20000微秒的更新间隔，游戏中常用
         *              SensorManager.SENSOR_DELAY_UI = 2：     对应60000微秒的更新间隔
         *              SensorManager.SENSOR_DELAY_NORMAL = 3： 对应200000微秒的更新间隔
         *              键入自定义的int值x时：对应x微秒的更新间隔
         */
        mSensorManager.registerListener(this, mSensorAcc, SensorManager.SENSOR_DELAY_GAME);
        mSensorManager.registerListener(this, mSensorMag, SensorManager.SENSOR_DELAY_GAME);
    }

    /**
     * 第五步：在失去焦点时注销传感器
     */
    @Override
    protected void onPause() {
        super.onPause();
        mSensorManager.unregisterListener(this);
    }

    /**
     * 获取方向角
     */
    public void getDistance() {
        new Timer().scheduleAtFixedRate(new TimerTask() {
            @Override
            public void run() {

            }
        }, Date.from(LocalDateTime.now().atZone(ZoneId.systemDefault()).toInstant()), time);
    }

    /**
     * 获取方向角
     */
    public void getAngle() {
        new Timer().scheduleAtFixedRate(new TimerTask() {
            @Override
            public void run() {


            }
        }, Date.from(LocalDateTime.now().atZone(ZoneId.systemDefault()).toInstant()), time);
    }


    /**
     * 显示蓝牙距离
     */
    public void displayDistance() {
        new Timer().scheduleAtFixedRate(new TimerTask() {
            @Override
            public void run() {
                // 方向角
                float[] inR = new float[9];
                float[] outR = new float[9];
                float[] orientationValues = new float[3];
                // 第一个是方向角度参数，第二个参数是倾斜角度参数
                SensorManager.getRotationMatrix(inR, null, accValues, magValues);
                // 根据当前上下文的屏幕方向调整与自然方向的相对关系。
                // 当设备的自然方向是竖直方向（比如，理论上说所有手机的自然方向都是都是是竖直方向，而有些平板的自然方向是水平方向），而应用是横屏时，
                // 需要将相对设备自然方向的方位角转换为相对水平方向的方位角。
                SensorManager.remapCoordinateSystem(inR, axisX, axisY, outR);
                SensorManager.getOrientation(outR, orientationValues);
                angle = (double) Math.round(Math.toDegrees(orientationValues[0]) * 100) / 100;
                MainActivity.this.runOnUiThread(() -> angleVale.setText(angle + ""));

                // 移动距离
                AtomicReference<Double> acceleration = new AtomicReference<>(0.0);
                new ArrayList<>(accelerationList).stream().mapToDouble(a -> a).average().ifPresent(acceleration::set);
                Log.e("accelerationList", String.valueOf(accelerationList));
                accelerationList.clear();
                distance = acceleration.get() / (2 * Math.PI * 0.5);
                Log.e("distance", String.valueOf(distance));
                MainActivity.this.runOnUiThread(() -> movingDistanceValue.setText(distance + ""));

                if (rssi != null) {
                    // 设置信号值
                    MainActivity.this.runOnUiThread(() -> signalValue.setText(rssi + ""));
                    doubleList.add(new Double[]{(double) System.currentTimeMillis(), 1D, 1D, 0D, 0D, distance, angle, rssi});

                    int size = doubleList.size();

                    if (size > 100) {
                        List<Double[]> newDoubleList = new CopyOnWriteArrayList<>();

                        for (int i = size - 100; i < size; i++) {
                            newDoubleList.add(doubleList.get(i));
                        }
                        doubleList.clear();
                        doubleList.addAll(newDoubleList);
                        newDoubleList.clear();
                    }

                    Double[][] doubleParam = new Double[doubleList.size()][];
                    for (int i = 0; i < doubleList.size(); i++) {
                        doubleParam[i] = doubleList.get(i);
                    }

                    // http://106.14.41.69:9999/
                    // http://3610816as6.qicp.vip:44631/
                    try {
                        HttpResponse execute = HttpUtil.createPost("http://106.14.41.69:9999/hcmed/ibeacon")
                                .body(JSONUtil.toJsonStr(doubleParam), "application/json;charset=utf-8")
                                .execute();
                        if (execute.isOk() && execute.body() != null) {
                            String body = execute.body();
                            distanceList.add(body);
                            if (distanceList.size() > 3) {
                                distanceList.remove(0);
                                Log.e("distanceList", String.valueOf(distanceList));
                                List<String> distances = new ArrayList<>(distanceList);
                                double asDouble = distances.stream().mapToDouble(Double::parseDouble).average().getAsDouble();
                                MainActivity.this.runOnUiThread(() -> signalDistanceValue.setText(String.valueOf(asDouble)));
                            }
                        } else {
                            MainActivity.this.runOnUiThread(() -> signalDistanceValue.setText("服务器连接异常"));
                        }
                    } catch (HttpException e) {
                        MainActivity.this.runOnUiThread(() -> signalDistanceValue.setText("服务器连接异常"));
                    }
                } else {
                    MainActivity.this.runOnUiThread(() -> signalDistanceValue.setText("正在获取信号"));
                }
            }
        }, Date.from(LocalDateTime.now().atZone(ZoneId.systemDefault()).toInstant()), time);
    }


    /**
     * 查找蓝牙设备
     */
    private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
        @RequiresApi(api = Build.VERSION_CODES.N)
        @Override
        public void onReceive(Context context, Intent intent) {
            if (!mBluetoothAdapter.isEnabled()) {
                Toast.makeText(MainActivity.this, "请打开蓝牙", Toast.LENGTH_LONG).show();
            }
            Log.e("bluetoothName", bluetoothName);
            bluetoothDevice = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
            // 发现的蓝牙设备名称不为空
            if (bluetoothDevice != null && StringUtils.isNotBlank(bluetoothDevice.getName())) {
                Log.e("bluetoothDeviceName", bluetoothDevice.getName());
                if (!bluetoothNameList.contains(bluetoothDevice.getName())) {
                    bluetoothNameList.add(bluetoothDevice.getName());
                    setSpinner(bluetoothNameList);
                }
                // 发现的蓝牙设备等于指定设备
                if (StringUtils.isNotBlank(bluetoothName) && bluetoothDevice.getName().equals(bluetoothName) && intent.getExtras() != null) {
                    rssi = (double) intent.getExtras().getShort(BluetoothDevice.EXTRA_RSSI);
                    Log.e("onReceive3", String.valueOf(rssi));
                }
            }
        }
    };

    /**
     * 所有运行API 23+（Android 6.0 +）的设备都需要此方法，Android必须以编程方式检查蓝牙的权限，仅清单中的put权限不足
     */
    private void checkPermission() {
        Log.e("onReceive", "checkPermission: Start");
        if (Build.VERSION.SDK_INT > Build.VERSION_CODES.LOLLIPOP) {
            this.requestPermissions(new String[]{Manifest.permission.ACCESS_FINE_LOCATION, Manifest.permission.ACCESS_COARSE_LOCATION, Manifest.permission.BLUETOOTH}, 1001);
        }
        Log.e("onReceive", "checkPermission: Finish");
    }

    /**
     * 蓝牙列表搜索
     */
    public void startDiscovery() {
        new Timer().scheduleAtFixedRate(new TimerTask() {
            @Override
            public void run() {
                if (mBluetoothAdapter.isDiscovering()) {
                    mBluetoothAdapter.cancelDiscovery();
                }
                mBluetoothAdapter.startDiscovery();
            }
        }, Date.from(LocalDateTime.now().atZone(ZoneId.systemDefault()).toInstant()), time);
    }

    /**
     * 数据求和
     *
     * @param array 数据
     * @return 求和
     */
    public Double sum(List<Double> array) {
        return array.stream().mapToDouble(x -> x).sum();
    }


    public void getJuLi(double rssi) {
        // 设置信号值
        MainActivity.this.runOnUiThread(() -> signalValue.setText(rssi + ""));
        doubleList.add(new Double[]{(double) System.currentTimeMillis(), 1D, 1D, 0D, 0D, distance, angle, rssi});

        int size = doubleList.size();

        if (size > 100) {
            List<Double[]> newDoubleList = new CopyOnWriteArrayList<>();

            for (int i = size - 100; i < size; i++) {
                newDoubleList.add(doubleList.get(i));
            }
            doubleList.clear();
            doubleList.addAll(newDoubleList);
            newDoubleList.clear();
        }

        Double[][] doubleParam = new Double[doubleList.size()][];
        for (int i = 0; i < doubleList.size(); i++) {
            doubleParam[i] = doubleList.get(i);
        }

        // http://106.14.41.69:9999/
        // http://3610816as6.qicp.vip:44631/
        try {
            HttpResponse execute = HttpUtil.createPost("http://106.14.41.69:9999/hcmed/ibeacon")
                    .body(JSONUtil.toJsonStr(doubleParam), "application/json;charset=utf-8")
                    .execute();
            if (execute.isOk() && execute.body() != null) {
                MainActivity.this.runOnUiThread(() -> signalDistanceValue.setText(execute.body()));
            } else {
                MainActivity.this.runOnUiThread(() -> signalDistanceValue.setText("服务器连接异常"));
            }
        } catch (HttpException e) {
            MainActivity.this.runOnUiThread(() -> signalDistanceValue.setText("服务器连接异常"));
        }
    }

    /**
     * 校验（求均值）
     *
     * @param view 视图
     */
    public void test(View view) {

        if (accList.size() > 100) {
            average = accList.stream().mapToDouble(a -> a).average().getAsDouble();
            Log.e("average", String.valueOf(average));
            MainActivity.this.runOnUiThread(() -> test.setText("已完成校验完成"));
            accList.clear();
        }
        doubleList.clear();
    }


    /**
     * 获取加速度
     */
//    public void getAcceleration() {
//        new Timer().scheduleAtFixedRate(new TimerTask() {
//            @Override
//            public void run() {
//
//                String accelerationStr = accelerationValue.getText().toString().replace("\n", "").replace("x", "").replace("y", "").replace("z", "").trim();
//                String magnetometerStr = magnetometerValue.getText().toString().replace("\n", "").replace("x", "").replace("y", "").replace("z", "").trim();
//                if (StringUtils.isNotBlank(accelerationStr) && StringUtils.isNotBlank(magnetometerStr)) {
//                    String[] tvAccList = accelerationStr.split(":");
//                    xAccelerationList.add(Double.parseDouble(tvAccList[1]));
//                    yAccelerationList.add(Double.parseDouble(tvAccList[2]));
//                }
//            }
//        }, Date.from(LocalDateTime.now().atZone(ZoneId.systemDefault()).toInstant()), 1000);
//    }


    /**
     * 获取距离
     */
//    public double getDistance() {
//        List<Double> xAccelerations = new ArrayList<>(xAccelerationList);
//        List<Double> yAccelerations = new ArrayList<>(yAccelerationList);
//        Log.e("xAccelerationList", String.valueOf(xAccelerationList));
//        Log.e("yAccelerationList", String.valueOf(yAccelerationList));
//        Log.e("xAccelerations", String.valueOf(xAccelerations));
//        Log.e("yAccelerations", String.valueOf(yAccelerations));
//        // 加速度获取时间间隔（毫秒）
//        double time = 0.02;
//        // List<Double> x_a = Arrays.asList(1.0, 2.0, 3.0, 4.0, -5.0);
//        // List<Double> y_a = Arrays.asList(0.0, 0.0, 0.0, 0.0, 0.0);
//        List<Double> xv = IntStream.range(0, xAccelerations.size()).mapToObj(i -> xvInIt + time * (sum(xAccelerations.subList(0, i + 1))) - xAccelerations.get(i) * time * 0.5).collect(Collectors.toList());
//        List<Double> yv = IntStream.range(0, yAccelerations.size()).mapToObj(i -> yvInIt + time * (sum(yAccelerations.subList(0, i + 1))) - yAccelerations.get(i) * time * 0.5).collect(Collectors.toList());
//
//        xvInIt = xvInIt + sum(xAccelerations) * time;
//        yvInIt = yvInIt + sum(yAccelerations) * time;
//
//        xAccelerationList.clear();
//        yAccelerationList.clear();
//        xAccelerations.clear();
//        yAccelerations.clear();
//        return Math.sqrt(Math.pow(sum(xv) * time, 2) + Math.pow(sum(yv) * time, 2));
//    }


}